package com.study.common

import android.annotation.SuppressLint
import android.text.TextUtils
import android.util.Patterns
import com.study.common.annotation.Desc
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.regex.Pattern

object VerificationUtil {


    /**
     * 根据〖中华人民共和国国家标准GB11643-1999〗中有关公民身份号码的规定，公民身份号码是特征组合码，由十七位数字本体码和一位数字校验码组成。
     * 排列顺序从左至右依次为：六位数字地址码，八位数字出生日期码，三位数字顺序码和一位数字校验码。
     * 顺序码: 表示在同一地址码所标识的区域范围内，对同年、同月、同 日出生的人编定的顺序号，顺序码的奇数分配给男性，偶数分配 给女性。
     * 第十八位数字(校验码)的计算方法为：
     * 1.将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为：7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
     * 2.将这17位数字和系数相乘的结果相加。
     * 3.用加出来和除以11，看余数是多少？
     * 4.余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为: 1 0 X 9 8 7 6 5 4 3 2;
     * 5.通过上面得知如果余数是2，就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10，身份证的最后一位号码就是2。
     */
    private object IdCardValidator {
        // 省,直辖市代码表
        private val codeAndCity = arrayOf(
            arrayOf("11", "北京"),
            arrayOf("12", "天津"),
            arrayOf("13", "河北"),
            arrayOf("14", "山西"),
            arrayOf("15", "内蒙古"),
            arrayOf("21", "辽宁"),
            arrayOf("22", "吉林"),
            arrayOf("23", "黑龙江"),
            arrayOf("31", "上海"),
            arrayOf("32", "江苏"),
            arrayOf("33", "浙江"),
            arrayOf("34", "安徽"),
            arrayOf("35", "福建"),
            arrayOf("36", "江西"),
            arrayOf("37", "山东"),
            arrayOf("41", "河南"),
            arrayOf("42", "湖北"),
            arrayOf("43", "湖南"),
            arrayOf("44", "广东"),
            arrayOf("45", "广西"),
            arrayOf("46", "海南"),
            arrayOf("50", "重庆"),
            arrayOf("51", "四川"),
            arrayOf("52", "贵州"),
            arrayOf("53", "云南"),
            arrayOf("54", "西藏"),
            arrayOf("61", "陕西"),
            arrayOf("62", "甘肃"),
            arrayOf("63", "青海"),
            arrayOf("64", "宁夏"),
            arrayOf("65", "新疆"),
            arrayOf("71", "台湾"),
            arrayOf("81", "香港"),
            arrayOf("82", "澳门"),
            arrayOf("91", "国外")
        )

        // 每位加权因子
        private val power = intArrayOf(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)

        // 判断18位身份证号码是否有效
        private fun isValidate18IdCard(idCard: String): Boolean {
            if (idCard.length != 18) {
                return false
            }
            val idCard17 = idCard.substring(0, 17)
            val idCard18Code = idCard.substring(17, 18)
            val c: CharArray
            val checkCode: String
            if (isDigital(idCard17)) {
                c = idCard17.toCharArray()
            } else {
                return false
            }

            val bit = coverCharToInt(c)
            val sum17 = getPowerSum(bit)

            // 将和值与11取模得到余数进行校验码判断
            checkCode = getCheckCodeBySum(sum17)
            // 将身份证的第18位与算出来的校码进行匹配，不相等就为假
            return idCard18Code.equals(checkCode, ignoreCase = true)
        }

        // 将15位的身份证转成18位身份证
        @SuppressLint("SimpleDateFormat")
        fun convertIdCardBy15bit(idCard: String): String {
            var idCard18 = ""
            if (idCard.length != 15) {
                return ""
            }

            if (isDigital(idCard)) {
                // 获取出生年月日
                val birthday = idCard.substring(6, 12)
                SimpleDateFormat("yyMMdd").parse(birthday)?.let {
                    val cDay = Calendar.getInstance()
                    cDay.time = it
                    val year = cDay[Calendar.YEAR].toString()

                    idCard18 = idCard.substring(0, 6) + year + idCard.substring(8)

                    val c = idCard18.toCharArray()
                    val bit = coverCharToInt(c)
                    val sum17 = getPowerSum(bit)
                    // 获取和值与11取模得到余数进行校验码
                    val checkCode = getCheckCodeBySum(sum17)
                    // 获取不到校验位
                    // 将前17位与第18位校验码拼接
                    idCard18 += checkCode
                }

            }
            return idCard18
        }

        // 是否全部由数字组成
        fun isDigital(str: String): Boolean {
            return "" != str && str.matches("^[0-9]*$".toRegex())
        }

        // 将身份证的每位和对应位的加权因子相乘之后，再得到和值
        fun getPowerSum(bit: IntArray): Int {
            if (power.size != bit.size) {
                return 0
            }
            var sum = 0
            for (i in bit.indices) {
                for (j in power.indices) {
                    if (i == j) {
                        sum += bit[i] * power[j]
                    }
                }
            }
            return sum
        }

        // 将和值与11取模得到余数进行校验码判断
        private fun getCheckCodeBySum(sum17: Int): String {
            return when (sum17 % 11) {
                10 -> "2"
                9 -> "3"
                8 -> "4"
                7 -> "5"
                6 -> "6"
                5 -> "7"
                4 -> "8"
                3 -> "9"
                2 -> "x"
                1 -> "0"
                0 -> "1"
                else -> ""
            }
        }

        @Desc("将字符数组转为整型数组")
        @Throws(NumberFormatException::class)
        private fun coverCharToInt(c: CharArray): IntArray {
            val a = IntArray(c.size)
            var k = 0
            for (temp in c) {
                a[k++] = temp.toString().toInt()
            }

            return a
        }

    }

    @Desc("判断手机号码是否有效")
    fun isValidTelNumber(telNumber: String): Boolean {
        if (!TextUtils.isEmpty(telNumber)) {
            val regex = "(\\+\\d+)?1[34578]\\d{9}$"
            return Pattern.matches(regex, telNumber)
        }

        return false
    }

    @Desc("判断用户名是否合法")
    fun isValidUserName(username: String): Boolean {
        if (!TextUtils.isEmpty(username)) {
            val regex = "^[a-zA-Z0-9_]+\$"
            return Pattern.matches(regex, username)
        }
        return false
    }

    @Desc("判断邮箱地址是否有效")
    fun isValidEmailAddress(emailAddress: String): Boolean {
        if (!TextUtils.isEmpty(emailAddress)) {
            return Patterns.EMAIL_ADDRESS.matcher(emailAddress).matches()
        }

        return false
    }

    @Desc("判断内容是否由字母，数字，下划线组成")
    fun isValidContent(content: String): Boolean {
        if (!TextUtils.isEmpty(content)) {
            val regex = "^[\\w\\u4e00-\\u9fa5]+$"
            return Pattern.matches(regex, content)
        }

        return false
    }
}